package baseFx.database.mybatis;

import baseFx.common.AutoCloseable;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
        , @Signature(type = Executor.class, method = "queryCursor", args = {MappedStatement.class, Object.class, RowBounds.class})})
public class ResultTypeInterceptor implements Interceptor {
    private static ThreadLocal<Class<?>> tag = new ThreadLocal<>();
    private static AutoCloseable empty = () -> {
    };

    public AutoCloseable setResultType(Class<?> type) {
        if (type == null) {
            return empty;
        }
        tag.set(type);
        return () -> tag.remove();
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Class<?> type = tag.get();
        if (type == null && ms.getResultMaps().isEmpty()) {
            type = Map.class;
        }
        if (type != null) {
            ResultMap.Builder rmBuilder = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), type, new ArrayList<>());
            MetaObject mo = ms.getConfiguration().newMetaObject(ms);
            mo.setValue("resultMaps", Arrays.asList(rmBuilder.build()));
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
